home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hottest 6
/
Hottest 6 (1996)(PDSoft)[!].iso
/
software
/
programming
/
c
/
shadow
/
docs
/
shadowlibrarymethods.doc
< prev
next >
Wrap
Text File
|
1978-11-24
|
100KB
|
2,328 lines
Shadow.library Documentation
Library Version 5.0
By David Navas
Updated: 13 Nov 1992
Copyright © 1992 by David Navas
All Rights Reserved
Method definition for the following classes as defined in SHADOW 5.0:
DirectorClass
MetaClass
MetaCluster
PatcherClass
ProcessClass
RootClass
RootCluster
What this document describes:
This document is meant to be a reference appendix much in the same way
that Appendix B in the RKM:Libraries 3rd edition (ISBN 0-201-56774-1)
is for BOOPSI. If you have not read either Chapter 12 of the
RKM:Libraries ("BOOPSI -- Object-Oriented Intuition"), or Appendix B
("BOOPSI Class Reference"), it is highly recommended that you peruse
them. Although SHADOW's object-oriented implementation is slightly
different than BOOPSI's, this reference attempts to mimic the RKM
layout as much as is reasonably feasible, and much common ground can
be found between the two.
Where BOOPSI is intended to address the needs of Intuition, SHADOW
attempts to address a more comprehensive superset of needs. As
such, while programming SHADOW is rather simple, understanding it
in its entirety can be intimidating.
This document does not profess to be an exhaustive overview of SHADOW
itself. Instead, its intent is to inform potential programmers of the
nuances of each of the individual method calls within each of the
available default classes.
OVERVIEW and REVIEW:
In SHADOW's version of the Object-Oriented Programming model, as with
BOOPSI's version, everything is an OBJECT. In particular, under SHADOW,
everything that deals with the Object-Oriented part of SHADOW begins
with the structure CoreObject [include:shadow/core.h] which is defined
as being a combination of the OBJECT's cob_class and its cob_useCount.
The cob_useCount of an OBJECT is used for resource tracking. For the
most part, in order to deal with this document, the cob_useCount is
not required to be fully understood. A broader discussion of it is
available elsewhere. All interaction with this field MUST proceed
via the DropObject() and UseObject() calls and the CheckUseCount()
macro.
The cob_class field is defined to be the "blueprints" of an object.
The object's ATTRIBUTEs (alternatively referred to as properties or
instance variables in other Object-Oriented Programming Models) and the
object's METHODs (alternatively referred to as functions in other
programming models) are all described in the OBJECT's cob_class.
[Special note:
If an OBJECT's cob_class is NULL, the longword after the CoreObject
is assumed to contain the size of the object so that the OBJECT
can be freed when the cob_useCount drops to zero during a
DropObject() call. NULL cob_class OBJECTs are useful to pass around
when large amounts of data need to be passed from program to
program -- and in particular, when they need to be passed in an
asynchronous, resource-tracked manner. A zero is a legal size for
the OBJECT (the longword after the CoreObject structure), and signals
a program's wish for DropObject() NOT to free the OBJECT when the
usecount falls to zero. see: 'struct ClasslessObject' in
include:shadow/core.h]
A cob_class is a special kind of OBJECT. It is guaranteed to contain
a Meta structure [include:shadow/coreMeta.h], which is a structure that
contains important method parsing and attribute parsing information,
AS WELL AS all the information contained in the CoreObject structure.
METAS:
This leads us to one of the most confusing elements of SHADOW --
if we label all cob_classes as "Classes", what is the cob_class of a
Class?
Imagine a row of identical apartments in an apartment complex. If
we model these apartments under an object-oriented paradigm, the
apartments are instances (or OBJECTs) of a particular apartment-class.
The apartment-class serves as a blueprint for each of the apartments,
and, indeed, it is compelling to refer to the apartment blueprints
AS the class of the apartments.
These blueprints, however, are also instances (or OBJECTs) of a
blueprint-class. The blueprint-class is itself described in numerous
architectural books. But architectural books are instances
(or OBJECTs) of a book-class. This seemingly infinite series of
statements must terminate somewhere, and in real life it usually
terminates at some fuzzy boundary of understanding. For example, while
most people would readily agree that an apartment must have a
blueprint, they would also have a great deal of trouble adequately
describing just what a blueprint contains.
Unfortunately, computers are stupid and lack the ability to deal with
this kind of "fuzzy understanding."
Fortunately, the reality is that this type of recursion always
terminates. A "book" is described in a "dictionary" and a "dictionary"
is described in itself. In short, we end in a self-referencing
recursion -- something is described by itself.
Under SHADOW, the responsibility of parsing attribute requests and
method requests for a Class (or any cob_class, for that matter) is
the domain of a Meta. A Meta is the "something" in SHADOW which
refers to itself. More concretely, SHADOW's Metas are OBJECTs
whose cob_class points back to itself.
A Meta contains the same type of information as a Class, excepting
that the OBJECT's cob_class points back to itself. This self-referencing
implies that all methods and attribute requests [ie: DoShadow(),
FindAttribute(), etc.) for Metas are handled by the Meta itself. This
also implies that a Meta is an instance of itself.
However, paradoxically, the instances of Metas are classes; or, less
ambiguously, the instances of Metas are OBJECTs which can legally
reside in the cob_class field of other OBJECTs. This implies,
correctly, that a Meta is just another kind of cob_class....
Metas exist for one main reason: METH_CREATE -- or, rather, the
flexibility in creating new Metas which define new ways of creating
object instances. For instance, the ability to create Metas gives
you, the programmer, the ability to create Classes that create
their instance OBJECTs via a calloc() call, instead of an AllocMem()
call.
All OBJECTs are created by sending an OOP METH_CREATE "message" to the
associated cob_class of the OBJECT you want created. Because all
methods of all objects are really handled by the cob_class of the
OBJECT, sending a "message" to a cob_class implies that the method
request is really "handled" by the cob_class' Meta. Hence, the only
way to change a program's "object creation" call is to "subclass" a
Meta, creating a new Meta and rebinding the METH_CREATE method to
your own code. [see: Figure.SLM.1]
If this has confused you, you may want to refer back to Introduction.doc
which also contains information about the distinctions between Metas,
cob_classes, OBJECTs, etc. It is important to understand the nuances
of Metas if you are to read this appendix in its entirety. If, instead,
you are merely trying to reference a particular method in a class
like PROCESS_CLASS, then Metas are not important to you.
OF SELECTORS, METHODS, and OOP MESSAGES:
The discussion two paragraphs above introduces the OOP term "message"
into a programming model where "message" is already used to refer to
passing data from task to task, or passing data across machines.
As page 293 of the RKM:Libraries points out:
"The term 'message' used in object oriented terminology can be [a]
little confusing to the Amiga programmer because the Boopsi
message has nothing to do with an Exec message."
The usage is similarly confusing under SHADOW. Object-oriented
terminology uses the word "message" as a means of selecting which
method (or function) to execute to complete the method invocation
request (DoShadow(), DoShadowAsync(), PreParseShadow(), etc.).
From now on, the less ambiguous terms "selector", "method", and
"invoke" will be used to describe the process of requesting and
servicing OOP "messages". The term selector will refer to the OOP
term "message". It is hoped that the terms "method" and "invoke" are
similarly easily understood. We can, therefore, now say that a
programmer requests a method (a function) by passing a selector
(METH_CREATE, METH_PROC_ASSOCIATE, etc.) to the correct invoking macro
or library function (CallSuper(), DoShadow(), DoShadowInProcess(),
DSM(), etc.). These terms are, hopefully, less ambiguous.
SELECTORS:
Under SHADOW, selectors are implemented as pointers to strings. This
allows for large, unambiguous name-spaces, and with a few
straight-forward naming conventions, eliminates the need to surpervise
the creation of third party selectors. SHADOW goes to a few lengths
to ensure that these strings have as little overhead on method
invocations as possible through the use of buffering method lookups,
and an implementation of a "strings" table which allows each string
that is used as a method-selector (or an attribute, class, etc.) to be
given a unique 32bit address.
Thus, if a selector is not found in the buffered lookup table (ie: the
method wasn't recently invoked), the selector is found in the hashed
array of system strings, and the 32bit returned value is used to
radix search through the MethodTable of the cob_class.
ATTRIBUTES:
Attributes are also "named" using strings. Attributes contain the
definition of the variables that are stored in an object. Each
named attribute can refer to an entire C-structure of variables,
allowing for the usual object-oriented separation of each subclass'
attributes from its associated superclass'. However, it is entirely
possible for a superclass to search for a subclass' set of variables
(as attributes, like methods, are bound at run-time, so no compilation
check can be done, and run-time checking would be prohibitive). Care
on the part of the programmer must be taken that either superclasses
don't know about their subclass' attributes, or aren't effected by
their absence or existence. In other words, for code such as:
SuperClassMethod(METHOD_ARGS, other_args)
{
struct MySubClassVars mscv = FindAttribute(object, ATTR_SUB_VARS);
.
.
.
}
...you must check "mscv" against NULL, and take the appropriate actions.
In most cases, however, you should avoid such behaviour.
CLUSTERS:
In addition to Classes, and as an example of "subclassing" Metas,
SHADOW defines Clusters as the cob_class of COMPOSITEs. A
COMPOSITE is sort of like a bag of OBJECTs. When the COMPOSITE is
fully initialized (see: METH_INIT), it contains a number of OBJECTs
stored in a binary tree. The attribute of this binary tree is
represented as ATTR_BAG. Therefore, you can get a pointer to the
binary tree (which is what y0u need to pass to the various binary tree
manipulation functions) by calling:
AVLTree *bt;
bt = (AVLTree *)FindAttribute(my_compositeObject, ATTR_BAG);
Or you can merely use the structure 'struct CoreComposite' and
de-reference directly off of that [include:shadow/coreRoot.h].
Once the COMPOSITE is initialized, you may add or remove as many
objects as you like to/from the ATTR_BAG binary tree. Caution: if you
remove an object, please remember to send the removed object a
METH_REMOVE method so that it can be removed from its cob_class'
instance tree as well.
INHERITENCE:
Methods are inherited from an object's cob_class' superclass, as are
attributes. Inheritence, subclassing, and superclasses are all terms
that should be familiar to you either from previous object-oriented
programming, or from your perusal of my Glossary.doc and the
RKM:Libraries 3rd edition BOOPSI discussions. Like Appendix B
in RKM:Libraries, this document describes each class in turn,
describing the new methods, the modified methods, the new attributes,
the superclass, and the include files that are associated with each
separate class.
Each class inherits methods and attributes from its superclass by
default. Therefore we will talk about classes in the order in which
they appear in the inheritence hierarchy. The hierarchy is as follows:
MetaClass
|
|
MetaCluster
RootClass
________/ | \__________
| | |
DirectorClass PatcherClass ProcessClass
RootCluster
CLASS OVERVIEW:
MetaClass and MetaCluster are the meta descriptions for Classes and
Clusters. These are rarely used directly by the end programmer.
They are used indirectly for such things as creating instances,
classes, and subclasses of themselves.
RootClass and RootCluster are the roots of the Class and Cluster
inheritence hiearchies They do things like store the object into the
class' ATTR_INSTANCETREE (a watched binary tree), and they define
clusters as starting with an ATTR_BAG. Again, these are rarely
directly used, they are more often used merely as classes to subclass.
DirectorClass is the class for director objects, usually referred to as
watchers. SHADOW defines a type of variable called WatchedVariables.
Director objects are the objects responsible for actually watching
these WatchedVariables. They provide Notification methods, and also
support the ability to watch more than one variable at a time via the
ESTABLISH/TERMINATE method protocol. Browser uses Director objects
(or watchers) in three separate ways.
Browser uses watchers to watch the instance tree of every opened
Meta/Class/Instance listing so that it can keep the listings as current
as possible. It also uses watchers to keep the "number of patches"
in the Method display windows current. In addition, browser uses
something known as a "class watcher" to watch all of the instances of
all of the subclasses of a certain class -- in this case, it watches
the ATTR_GUICHILDREN of all windows and gets notification every time
a window has a child (usually a gadget) added or removed from the
ATTR_GUICHILDREN tree.
PatcherClass is the class for method patch objects. Every method in
SHADOW can be patched -- this is SetFunction() done right! Method
patches for a class are located in a watched list referred to as
ATTR_PATCHEDVERBS. Patches have a priority (higher priority patches
get invoked before lower priority patches -- regular methods are default
priority zero), can dynamically prevent subsequent patches of lower
priority from being invoked, and may only patch a single verb at a time,
unlike watchers. Please Note!: it is impossible to patch the DESTROY
method -- see RemoveAllPatches() for more details.
Patches are useful when attempting to change the behaviour of some
non-native application, some feature of some class you don't like,
or for distributing bug fixes.
ProcessClass (more accurately referred to as ThreadClass, because of
the way AmigaDOS treats Tasks/Processes) is the class for process
objects. They attach themselves to your task->tc_UserData field,
SO DON'T MESS WITH THAT FIELD! Process objects keep track of IPC
ports, the parent task pointer (0 if no parent), the message for use
during synchronous communications, etc. Each program that intends
to invoke methods, either actively via DoShadow() or DSM(), or
passively via DropObject() or possibly even via callbacks in the
FindAttribute() code, should generally call InitOOProgram().
Unfortunately, this makes subclassing ProcessClass for your own
program's process more or less pointless because InitOOProgram()
associates a default process to your already running program.
Fortunately, because METH_SUB is actually a callback method, it is safe
to create a subclass of Process Class and then send that class a
METH_CREATE followed by a METH_PROC_ASSOCIATE as documented later in
this file. The attribute ATTR_SHADOWPROCESS -must- be located eight
bytes from the start of the object, so please don't define your own
private process-class unless it is a subclass of ProcessClass.
The exact contents of ATTR_SHADOWPROCESS are subject to change, and in
fact HAVE changed from version 4 to version 5!
Processes have become generally more useful in version 5 because of
the much cleaner startup conventions, and the plethora of new
method invocation possibilities. ASLClass, for instance,
-automatically- starts up a new process each time a new AslObject
would block the main gui process.
METHOD CALLING CONVENTIONS
All methods are invoked by DSM() with at least four parameters. The
first is a pointer to an IPCMessage structure. If this parameter is
non-NULL, it means that the method was invoked with an asynchronous
method, and the passed IPCMessage is the message which was sent to the
task. The name of this parameter is 'msg'.
The second parameter is the object that the method was invoked on.
However, the term 'object' would be ambiguous, as the instance that
the method was invoked on may well be a class-object or a meta-object.
Nevertheless, in the code, the parameter is named 'object'. In other
object-oriented languages, this is often defined to be 'self' or 'this'.
If you prefer this notation, the definition of METHOD_ARGS can be found
in include:shadow/misc.h. Feel free to change them for your own
convenience.
The third parameter is the class pointer, which is the pointer to
the class for which the method is defined (under the hierarchy of the
object->cob_class, of course). The parameter's name in the code is
'class'.
The last default parameter is the selector itself. This is guaranteed
to be a pointer to the system string which stores the name of the
method. This parameter is named 'MethodID'.
All four of these parameters can be found in the METHOD_ARGS #define in
the include file: shadow/misc.h.
SYSTEM CLASS REFERENCE
Class: META_CLASS
Superclass: -none-
Include File: <shadow/coreMeta.h>
This is the universal meta for all other metas.
Attributes:
ATTR_CORE -- The minimal class variables, including the
attribute and method table pointers.
Implemented as struct Meta and typedef'd
as META.
Access to this attribute is priviledged,
and usually unnecessary anyway.
ATTR_PATCHEDVERBS -- Watched list of method patches.
Access to this attribute is managed through
the method patching class.
ATTR_INSTANCETREE -- Watched binary tree of meta's instances.
Metas are kept on a special watched binary
tree located in ShadowBase->sb_metaTree.
Classes (as instances of MetaClass) are
kept on this INSTANCETREE. Note that even
though Metas are, strictly, instances of
themselves, they do not exist on their
own INSTANCETREE.
The Class Browser uses the watched aspect
of this binary tree and gets notification
whenever any new Class is created and
added to this tree. Instances are added
to the tree when the METH_INIT is sent to
them.
New Methods:
METH_CREATE
run as:
function in invoker's process.
arguments:
none.
NOTE: this function may NOT be invoked asynchronously!
Returns a pointer to an uninitialized object. Sets an
error in the current process error field if it can't
allocate an object-class "CANNOT_ALLOCATE_OBJECT"
[see include:shadow/misc.h]
purpose:
CreateInstance() uses this method to create a new instance
of a class. Programs which prefer to invoke the method
directly can as well, however there is no known
reason why programs would wish to do so, except,
perhaps, for testing purposes.
restrictions:
none
function:
Allocates an instance of a particular class. IE:this is a
method which is sent to a Class, not its instances.
It creates an object, fills in the class field and any
default attribute values as specified in the class attribute
table, and returns the allocated object.
Note that this object CANNOT have anything done to it UNTIL
it is sent a METH_INIT. Among other things, the useCount is
zero. DSM() correctly fails and frees the object if invoking
the METH_INIT fails for any reason (like the destination
process has it's port closed, or memory is running low).
Memory is allocated :: (MEMF_PUBLIC | MEMF_CLEAR)
example:
.
.
.
/*
* Allocation example code.
*/
procClass = FindShadowClass(PROCESS_CLASS);
procObject = DoShadow(procClass,
NULL,
METH_CREATE,
METHOD_END);
procObject = DoShadow(procObject,
NULL,
METH_INIT,
METHOD_END);
DropObject(procClass);
.
.
.
/*
* Cleanup code.
*/
RemovObject(procObject);
METH_DESTROY
run as:
function in invoker's process.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
function:
Invalidates the cache for any cache lines with the class
being destroyed. See InvalidateCache() for details.
Frees any leftover watchers on the class
[FreeObjectWatchers()], destroys the method and attribute
tables, drops the class name and superclass references,
frees the object, drops its class, and handles the case of
transferring the pointer from the 'msg' field to
non-existence, just in case this method is invoked
asynchronously (which should NEVER happen). This is the
second half of the two-level resource tracking. This
function is invoked by DropObject() when the useCount of
the object drops to zero, implying no one has a pointer to
the object. As evidenced by the FreeObjectWatchers() call,
this may not be entirely TRUE, but watchers are a special
case.
Also calls RemoveAllPatches().
example:
/*
* Assuming the assert works, the DropObject()
* invokes the METH_DESTROY method.
*/
assert(CheckUseCount(object) == 1);
DropObject(object); /*
* This calls the METH_DESTROY method.
* This is the only legal way to have
* the METH_DESTROY method called.
*/
/*
* NOTE!!!! In practice, you do not assert() usecounts
* like this anymore than you would assert any other kind
* of usecount. In real life, the DropObject() calls
* the object's METH_DESTROY method whenever the usecount
* falls to zero. If the usecount is one before entering
* DropObject(), then the usecount obviously falls to
* zero, and the METH_DESTROY is then called. The assert
* is there only to differentiate the many calls you can
* make to DropObject() that do NOT invoke the
* METH_DESTROY method from this case, which does.
*/
METH_INIT
run as:
function in invoker's process.
arguments:
JSTR -- name of the class to create
JOBJ -- optional superclass of the class to create.
TAGL -- NULL terminated array of struct AttributeTag. NULL
is also valid.
TAGL -- NULL terminated array of struct MethodTag. NULL is
also valid.
Returns a pointer to the initialized object. NULL on
failure. Object destroyed on failure....
purpose:
Initializes the class or meta by filling in the superclass,
methods, and attributes of the new class or meta.
Call this method directly ONLY when you are creating
your own root of a "class" or meta hierarchy. Otherwise,
the METH_SUB is far more useful.
restrictions:
Call this directly only for "root"s of cob_class
hierarchies.
function:
Methods that are defined in metas have a rather disturbing
property. Recall that metas are responsible for handling
their own methods AS WELL AS the methods of their
instances.
However, the normal path of execution for a METH_INIT is to
initialize all variables of the object being defined. As
noted in the "purpose" field above, this includes the
method and attribute arrays of the class/meta being
defined. It is clearly impossible, therefore, for a meta
to completely handle its own METH_INIT. What gives?
Well, creation of "root" metas (that constitutes the
META_CLASS -- META_CLUSTER is a subclass of META_CLASS)
requires a call to the library function CreateMeta().
CreateMeta() actually fills in the meta's method and
attribute fields, and then invokes the METH_INIT on the
(half-filled) meta.
Therefore, it is up to this method call to distinguish
the distinction between half-filled metas, and completely
empty classes. This is accomplished by comparing
object->cob_class to object. Recall that ALL metas are
self-referencing by nature -- self-referencing in that
the object->cob_class field points back to object. So,
the METH_INIT distinguishes between the cases and takes
the appropriate actions as listed below:
If the method is being invoked on a meta,
the superclass, attribute array, instance size, and
method array are left alone.
Otherwise, if the method is being invoked on a class
that is not a meta, this function fills in the
superclass, the attribute table, the instance size,
and the method table.
In either case, it fills in the class name, binds all the
appropriate class watchers for its attributes [Ed:
watched variables have both a list of watchers, and a
pointer to a second list of watcher. SHADOW uses this
second pointer to point to a list of watchers managed by
the class. Under MetaClass and MetaCluster, these 'class'
watchers are copied into all subclasses. See
BindSuperWatchers() for more details], and adds the object
into its class' ATTR_INSTANCETREE. In the case of a meta,
this would be Shadow->sb_metaTree. It also calls
BindWatchers() on the object which binds the second
watch-list pointer of all watched variables to the class'
attributes' SList. See the struct Attribute definition and
the AutoDocs for BindWatchers().
example:
/*
* Retrieve the meta in which to create the base class.
*/
metaclass = FindWatchedTreeStringNode(
&ShadowBase->sb_metaTree,
META_CLASS);
/*
* Create the base class.
*
* myRootClustAttributes is a NULL terminated array
* of AttributeTag structures.
* myRootClustMethods is a NULL terminated array of
* MethodTag structures.
*/
myroot = CreateInstance(metaclass, NULL,
NULL,
MY_ROOT_CLASS,
NULL,
myRootClassAttributes,
myRootClassMethods,
METHOD_END);
DropObject(metaclass); /*
* Don't need the metaclass
* pointer anymore.
*/
.
.
.
/*
* Cleanup!
*/
RemoveObject(myroot);
.
.
.
/*
* Creation of MetaClass:
*/
struct InitMeta __far globalIM = {
NULL,
NULL,
NULL, /* METH_INIT is default */
META_CLASS, /* meta name */
NULL, /* no super. */
metaClassAttrs,
metaClassMethods,
METHOD_END,
};
metaclass = CreateMeta(&globalIM);
.
.
.
/*
* Cleanup!
*/
RemoveObject(metaclass); /* this meta
* no longer needed.
*/
METH_REMOVE
run as:
function in invoker's process.
arguments:
none
purpose:
Removes a class from the system list, initiates the first
pass of the two-level resource tracking algorithm.
Call this method when you are done with a class and want
it to be removed from being referenced by the system. The
class will continue to exist until all references to it are
gone -- that implies that all instances of the class are
gone as each instance of a class is pointed to by the
instance's cob_class field.
RemoveObject() calls the METH_REMOVE function to Remove
classes and objects.
restrictions:
After calling this method, you may not have circular
references to this item, nor may you cause such
circular references to come into existence.
function:
Frees all class watchers associated with this class. See
FreeClassWatchers() for further details. Removes the
instance (in this method, the instance is a Class) from its
class' ATTR_INSTANCETREE. If this is a Meta being removed,
the Meta is removed from ShadowBase->sb_metaTree instead.
This is the first of the two-level resource tracking done
on objects. In addition, removal from this tree implies
that the system can no longer find your class/meta,
effectively removing it from the system. It is not
destroyed, however, until no one has a pointer to it
(assuming they have used UseObject() and DropObject()
appropriately. All self-references, either direct or
indirect, should be eliminated in this method.
example:
/*
* Cleanup code.
*/
RemoveObject(FindShadowClass(MYDOS_CLASS));
/*
* FindShadowClass() returns a used class
* pointer to MYDOS_CLASS.
* RemoveObject() then invokes the METH_REMOVE
* method, and DropObject()s the passed class.
*/
.
.
.
/*
* More example Cleanup Code.
* Assumes DosClass is already a valid pointer to your
* class.
*/
RemoveObject(DosClass);
/*
* RemoveObject() invokes the METH_REMOVE on
* DosClass and DropObject()s the passed
* class.
* DosClass is no longer a valid pointer
* to the DosClass object anymore. Indeed,
* the DosClass itself may very well have
* disappeared.
*/
.
.
.
METH_SUB
run as:
function in invoker's process.
arguments:
JSTR -- name of the class to create
JOBJ -- optional superclass of the class to create. This
method is, however, sent to the class that is to
be subclassed, so if this parameter is NULL, it
defaults to the object which the method was sent to.
TAGL -- NULL terminated array of struct AttributeTag. NULL
is also valid.
TAGL -- NULL terminated array of struct MethodTag. NULL is
also valid.
purpose:
Creates a new subclass.
CreateSubClass() calls this method.
You should probably use CreateSubClass(), but it takes
parameters exactly equivalent to what's shown here, so
it's good to reference this method when you need to
know the arguments to pass to CreateSubClass().
This is basically equivalent to a METH_CREATE followed
by a METH_INIT where the object you invoke the
METH_SUB on ends up being the superclass sent into the
METH_INIT.
restrictions:
none
function:
Note the description of the complications of sending
METH_INITs to metas in the METH_INIT description
above. Note that the METH_SUB is really just a
convenient wrapper around the METH_CREATE and the
METH_INIT methods.
If this method is invoked on a meta (that is, if object ==
object->cob_class), then instead of invoking METH_CREATE
and METH_INIT, this function MUST call CreateMeta() in
order to setup the methds, attributes, etc. of the meta.
In this case, the CreateMeta() is called with the InitMeta
structure set as the parameter list passed into METH_SUB
(minus the 'msg' pointer). CreateMeta() then calls the
METH_INIT method as described in the CreateMeta() autodoc.
The return value is equivalent to whatever CreateMeta
returns.
Otherwise, if the method isn't invoked on a meta, this
method instantiates a meta (creating a Class Object)
and sends a METH_INIT to it, returning whatever the INIT
method returns.
examples:
/*
* Creates a new class as a subclass of rootclass.
*/
newClass = CreateSubClass(NULL, ROOT_CLASS,
META_CLASS,
MYDOS_CLASS,
NULL,
my_new_attributes,
my_new_methods,
METHOD_END);
/*
* Creates a new class as a subclass of some private class.
*/
newClass2 = CreateSubClass(oldClass, NULL,
NULL,
MY_NEW_CLASS,
NULL,
my_new_attributes,
my_new_methods,
METHOD_END);
/*
* Creates a new meta as a "sub-meta" of metaclass.
*/
newMeta = CreateSubClass(NULL, META_CLASS,
NULL,
MY_META,
NULL,
my_new_attributes,
my_new_methods,
METHOD_END);
/*
* Note: CreateSubClass is a stub routine that calls
* METH_SUB.
*
* Note2: Don't forget to cleanup your allocations!
*/
METH_SUPER
run as:
function in invoker's process.
arguments:
JSTR -- name of the class to create
JOBJ -- optional subclass of the class to override. This
method is, however, sent to the class that is to
be "superClassed", so if this parameter is NULL, it
defaults to the object which the method was sent to.
TAGL -- NULL terminated array of struct AttributeTag. NULL
is also valid.
TAGL -- NULL terminated array of struct MethodTag. NULL is
also valid.
purpose:
Creates a new superclass for an existing class.
Thus, in effect, adding methods to an existing class tree.
restrictions:
The new superClass must be created as a subclass of the
passed class' superclass [that is, the superclass of the
object (class) the method was invoked on].
The class must HAVE a superClass -- ie: you cannot
invoke this method on ROOT_* classes.
This new class may NOT add any new attributes.
function:
The METH_SUB method is invoked on the passed class'
superclass. The InsertSuperClass() function is
then called (this function flushes the method cache as
well!).
examples:
/*
* Creates a new superclass of a subclass.
* Adds the methods specific in the my_new_method structure.
*/
procClass = FindShadowClass(PROCESS_CLASS, META_CLASS);
newClass = DoShadow(procClass, NULL, METH_SUPER,
MY_INTERMEDIATE_CLASS,
NULL,
my_new_attributes,
my_new_methods,
METHOD_END);
DropObject(procClass);
.
.
.
RemoveObject(newClass);
Class: META_CLUSTER
Superclass: META_CLASS
Include File: <shadow/coreMeta.h>
This is an example of a "submeta". It is really only intended
for demonstration purposes. If you find a use for it yourself,
so much the better!
MetaCluster is the blueprints for a class that creates a placeholder
for any number of other objects, and then creates those other
objects as well. For example, you can create a workbench-icon
cluster which describes a workbench icon as a collection of a file
object and a graphic object. When the cluster is instantiated
(creating a composite-object), the composite-object would have, as one
of its attributes, a binary tree with the newly instantiated file and
graphic objects in it.
Attributes:
ATTR_CLASSTABLE -- struct ClusterClassTable
[see: include:shadow/coremeta.h].
An array of classes that describes
what objects the cluster should instantiate
to put in the composite-object's binary tree.
Modified Methods:
METH_DESTROY
run as:
function in invoker's process.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
function:
ATTR_CLASSTABLE is freed.
Method is then routed to the superclass.
example:
See example under META_CLASS
METH_INIT
run as:
function in invoker's process.
arguments:
JSTR -- name of the class to create
JOBJ -- optional superclass of the class to create.
TAGL -- NULL terminated array of struct AttributeTag. NULL
is also valid.
TAGL -- NULL terminated array of struct MethodTag. NULL is
also valid.
TAGL -- NULL terminated array of classes to fill in the
ATTR_CLASSTABLE. NULL is also valid.
Returns a pointer to the initialized object. NULL on
failure. Object destroyed on failure....
purpose:
Initializes the class or meta by filling in the superclass,
methods, and attributes of the new class or meta.
Call this method directly ONLY when you are creating
your own root of a "class" or meta hierarchy. Otherwise,
the METH_SUB is far more useful.
restrictions:
Call this directly only for "root"s of cob_class
hierarchies.
function:
Please refer to the note about meta creation in the
METH_INIT method function description of META_CLASS.
This method creates the array for the ATTR_CLASSTABLE
attribute.
The method is then routed to the superclass.
example:
/*
* Retrieve the meta in which to create the base class.
*/
metacluster = FindWatchedTreeStringNode(
&ShadowBase->sb_metaTree,
META_CLUSTER);
/*
* Create the base cluster.
*
* myRootClustAttributes is a NULL terminated array
* of AttributeTag structures.
* myRootClustMethods is a NULL terminated array of
* MethodTag structures.
* myRootClustClasses is a NULL terminated array of
* class -pointers-.
*/
myroot = CreateInstance(metacluster, NULL,
NULL,
MY_ROOT_CLUSTER,
NULL,
myRootClustAttributes,
myRootClustMethods,
myRootClustClasses,
METHOD_END);
DropObject(metacluster); /*
* Don't need the metaclass
* pointer anymore.
*/
.
.
.
/*
* Cleanup!
*/
RemoveObject(myroot);
.
.
.
METH_SUB
run as:
function in invoker's process.
arguments:
JSTR -- name of the class to create
JOBJ -- optional superclass of the class to create. This
method is, however, sent to the class that is to
be subclassed, so if this parameter is NULL, it
defaults to the object which the method was sent to.
TAGL -- NULL terminated array of struct AttributeTag. NULL
is also valid
TAGL -- NULL terminated array of struct MethodTag. NULL is
also valid.
TAGL -- NULL terminated array of classes to fill in
ATTR_CLASSTABLE with. NULL is also valid.
purpose:
Creates a new subclass.
Adds an additional class_array parameter which is forwarded
to the METH_INIT method.
See the desription of the METH_SUB method purpose in
META_CLASS description above.
restrictions:
none
function:
Functionally identical to the METH_SUB in META_CLASS except
that this method forwards the class_array parameter to
the METH_INIT of META_CLUSTER.
example:
/*
* Creates a brand new meta for clusters.
*/
metaclass = FindWatchedTreeStringNode(
&ShadowBase->sb_metaTree,
META_CLASS);
metaCluster = DoShadow(metaclass,
NULL,
METH_SUB,
META_CLUSTER,
metaclass,
metaClusterAttrs,
metaClusterMethods,
METHOD_END);
DropObject(metaclass); /*
* Uninterested in this pointer
* now.
*/
/*
* Creates a new class as a subclass of rootcluster.
*/
newCluster = CreateSubClass(NULL, ROOT_CLUSTER,
META_CLUSTER,
MY_CLUSTER,
NULL,
my_new_attributes,
my_new_methods,
my_new_classes,
METHOD_END);
Class: ROOT_CLASS
Superclass: -none-
Include File: <shadow/coreRoot.h>
This is the root cob_class for all META_CLASS classes.
Attributes:
none
Methods:
METH_DESTROY
run as:
function in invoker's process.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
function:
Frees any leftover watchers on the object
[FreeObjectWatchers()], frees the object, and drops its
class. Handles the case of transferring the pointer from
the 'msg' field to non-existence, just in case this method
is invoked asynchronously (which should NEVER happen).
This is the second half of the two-level resource tracking.
This function is invoked by DropObject() when the usecount
of the object drops to zero, implying no one has a pointer
to the object. As evidenced by the FreeObjectWatchers()
call, this may not be entirely TRUE, but watchers are a
special case.
example:
See example under META_CLASS
METH_INIT
run as:
function in invoker's process
arguments:
JSTR -- name of the object to create (optional). If
specified, object stored on ATTR_INSTANCETREE is
sorted by the address of the string, rather than
the address of the object itself.
Returns a pointer to the initialized object. NULL on
failure.
purpose:
Initializes the object and makes it a part of the
system-shared resources.
In reality, ROOT_CLASS exists to be subclassed.
restrictions:
none
function:
Adds object to ATTR_INSTANCETREE of its class, either sorted
by the address of the passed string, or, if NULL string, by
the object's own address. Note that these are AVL trees,
so the tree remains well-balanced, regardless of the ordering
of allocated memory.
Also calls BindWatchers() to bind all the watched attributes
of the object's second List to the class attribute's watched
list. See BindWatchers() for more details.
example:
/*
* Create an instance of ROOT_CLASS
*/
rootObject = CreateInstance(NULL, ROOT_CLASS,
META_CLASS,
MY_OBJECT_NAME,
METHOD_END);
.
.
.
/*
* Cleanup!
* NOTE!!! You must call the METH_REMOVE directly
* with the name of the object or the removal will
* not occur correctly (ie: not at all).
*/
DoShadow(rootObject, NULL, METH_REMOVE, MY_OBJECT_NAME,
METHOD_END);
/*
* Note2: usually you keep the object name in the object's
* instance as handled by some superclass. It is highly
* suggested that you put such names into the FIRST
* attribute as the FIRST field for future compatibility
* reasons.
*/
DropObject(rootObject);
METH_REMOVE
run as:
function in invoker's process.
arguments:
JSTR -- optional string under which the object might have
been stored (in the ATTR_INSTANCETREE). Iif the
METH_INIT was invoked with a string as a
parameter, then the METH_REMOVE better be, or it
will fail to work properly.
purpose:
Removes an object from the class' ATTR_INSTANCETREE.
Initiates the first pass of the two-level resource tracking
algorithm. Call this method when you are done with an
object and want it to be removed from being referenced by
the system. The object will continue to exist until all
references to it are gone.
RemoveObject() calls the METH_REMOVE function to Remove
classes and objects.
restrictions:
If you called the METH_INIT on this object with a non-NULL
name-parameter, you MUST call the METH_REMOVE with this
same name!
After calling this method, you may not have circular
references to this item, nor may you cause such
circular references to come into existence.
function:
Removes the object from its class' ATTR_INSTANCETREE.
example:
see the METH_INIT method example for this class above.
Class: ROOT_CLUSTER
Superclass: -none-
Include File: <shadow/coreRoot.h>
This is the root cob_class for all META_CLUSTER clusters.
Attributes:
ATTR_BAG -- binary tree which all objects are stored on.
NOT a watched binary tree!
Modified Methods:
METH_DESTROY
run as:
function in invoker's process.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
function:
Removes all objects on the composite's ATTR_BAG and sends
a METH_REMOVE to all of them.
Method is then routed to the superclass.
example:
See example under META_CLASS
METH_INIT
run as:
function in invoker's process
arguments:
JSTR -- name of the object to create (optional). If
specified, object stored on ATTR_INSTANCETREE is
sorted by the address of the string, rather than
the address of the object itself.
Returns a pointer to the initialized object. NULL on
failure.
purpose:
Initializes the object and makes it a part of the
system-shared resources.
In reality, ROOT_CLUSTER exists to be subclassed.
restrictions:
none
function:
METH_CREATEs and METH_INITs (without arguments) all
objects whose classes are on the ATTR_CLASSTABLE of this
composite's cluster. Objects are stored on the ATTR_BAG's
binary tree under the name of the class.
Method continues in exactly the way that the METH_INIT
method does in the ROOT_CLASS as described above.
example:
/*
* Create an instance of ROOT_CLUSTER
*/
rootObject = CreateInstance(NULL, ROOT_CLUSTER,
META_CLUSTER,
MY_OBJECT_NAME,
METHOD_END);
.
.
.
/*
* Cleanup!
* NOTE!!! See notices in the METH_INIT example oF
* ROOT_CLASS above.
*/
DoShadow(rootObject, NULL, METH_REMOVE, MY_OBJECT_NAME,
METHOD_END);
DropObject(rootObject);
METH_REMOVE
run as:
function in invoker's process.
arguments:
JSTR -- optional string under which the object might have
been stored (in the ATTR_INSTANCETREE). If the
METH_INIT was invoked with a string as a
parameter, then the METH_REMOVE better be, or it
will fail to work properly.
purpose:
Removes a composite from the cluster's ATTR_INSTANCETREE.
Initiates the first pass of the two-level resource tracking
algorithm. Call this method when you are done with a
composite and want it to be removed from being referenced by
the system. The composite will comtinue to exist until all
references to it are gone.
RemoveObject() calls the METH_REMOVE function to Remove
all classes and objects.
restrictions:
If you called the METH_INIT on this composite with a
non-NULL name-parameter, you MUST call the METH_REMOVE with
this same name!
After calling this method, you may not have circular
references to this item, nor may you cause such
circular references to come into existence.
function:
Removes the composite from its clster's ATTR_INSTANCETREE.
example:
see the METH_INIT method example for this cluster above.
Class: DIRECTOR_CLASS
Superclass: ROOT_CLASS
Include File: <shadow/watcher.h>
The class that creates watchers to establish notification of changes
to watched variables.
Attributes:
ATTR_MANAGER -- struct ManagementNode
[see: include:shadow/watcher.h].
The place where useful information about the
director is stored. For instance, information
managing the conditions under which
notification is sent, and to whom
it is sent.
ATTR_DIRECTOR -- a WatchedList. It is a list of all the
established connections that have been made;
in short, a list of all objects this Director
is watching. Interestingly, you can get
notification of when the notification lists
change. And, of course, you can even have a
class watcher watch everything at once!
New Methods:
METH_DIRECTOR_ESTABLISH
run as:
function in invoker's process.
arguments:
APTR -- the attribute-name of the object to watch, or a
pointer to the actual watchedVariable, if no
object is specified. This implies that this
method CANNOT be safely invoked ASYNCronously.
JOBJ -- the object in which the WatchedVariable is. If
this parameter is NULL, the method assumes that
the APTR is a pointer to the WatchedVariable, and
not the name of the attribute.
long -- priority of the watcher.
Returns a handle to the connection. You should either
DropObject() the handle, or keep it to pass to the
TERMINATE method, after which you should DropObject() it....
purpose:
Use this watcher to watch a particular watched variable.
You should be prepared to service notifications of
changes prior to invoking this method.
All connections through a single "watcher" (or "director-
object") will have notification sent to the ONE destination
that that watcher had set up for it in its METH_INIT code.
restrictions:
May not be called asynchronously by DSM(). By default,
this method is never run asynchronously.
function:
Establishes a connection and adds that connection to the
ATTR_DIRECTOR list of connections. Uses either
AddClassWatcher() or AddWatcherNode(), depending on the
type of Watcher this director-object is. Please see the
AutoDocs for more information on these functions.
The Watcher may either be a SHADOW_OBJECT watcher or a
SHADOW_CLASS watcher. This is specified in the flags
argument to the METH_INIT.
examples:
/*
* Create a director object.
* This is an example of a class watcher.
*/
GlobalDirector = CreateInstance(NULL,
DIRECTOR_CLASS,
META_CLASS,
"WatchWindows",
object,
METH_DIRECTOR_NOTIFY,
(W_INSERT_NODE | W_REMOVE) |
(SHADOW_CLASS << 16) |
W_FLAG_AUTOBREAK |
W_FLAG_AUTOREMOVE,
METHOD_END);
/*
* Establish the actual connection. We don't care if
* GlobalDirector wasn't created successfully (ie: it is
* NULL), so that makes things easier.
*
* We are watching all the ATTR_GUICHILDREN of every instance
* whose class is a subclass of WINDOW_CLASS
*/
windowClass = FindShadowClass(WINDOW_CLASS);
DropObject(DoShadow(GlobalDirector,
NULL,
METH_DIRECTOR_ESTABLISH,
ATTR_GUICHILDREN,
windowClass,
METHOD_END));
DropObject(windowClass);
.
.
.
/*
* Cleanup!
*
* Note, because we INIT'd the director with the AUTO_BREAK,
* the director's connections are terminated when the
* METH_REMOVE is sent.
*
* Because we dropped the actual handle that the
* ESTABLISH method returned, this is the only way we
* can terminate the connection!
*/
RemoveObject(GlobalDirector);
----------
/*
* This is an example of an object watcher.
*/
/*
* Create the director to watch the children of this object.
*
* When this object's children reaches zero, this object
* should GO AWAY!
*/
director = CreateInstance(NULL,
DIRECTOR_CLASS,
META_CLASS,
"WatchBlockedChildren",
object,
METH_DIRECTOR_NOTIFY,
(W_INSERT_NODE | W_REMOVE) |
(SHADOW_OBJECT << 16) |
W_FLAG_AUTOBREAK |
W_FLAG_AUTOREMOVE,
METHOD_END);
/*
* Establish the conection for the director.
*/
handle = DoShadow(director,
NULL,
METH_DIRECTOR_ESTABLISH,
ATTR_GUICHILDREN,
object, /* object being watched */
METHOD_END))
.
.
.
/*
* Cleanup!
*/
DoShadow(director, NULL, METH_DIRECTOR_TERMINATE, handle,
METHOD_END);
/*
* Note: because this director was METH_INIT'd as
* W_FLAG_AUTOREMOVE, there is no reason to call
* RemoveObject() on the director as the METH_REMOVE
* has already been sent. Recall, however, that
* RemoveObject() both sends the METH_REMOVE and
* drops the object from further use. DropObject(),
* therefore, still needs to be called....
*/
DropObject(director);
METH_DIRECTOR_TERMINATE
run as:
function in invoker's process.
arguments:
JOBJ -- either the handle as returned by the ESTABLISH
method, or a pointer to the object from which a
watcher should be removed. The latter case
should be restricted to the
Free[Object|Class]Watchers() functions. Mostly
because you are not guaranteed which handle of
the watcher is removed. For instance, if one
watcher is watching more than one watched
variable of a single object, then invoking
TERMINATE with the object being watched may
release the watcher from any of those watched
variables.
long -- flags dictating whether this is a handle, or
the object being watched, not specifying
this parameter defaults to the type 'handle'
(0), the other case is W_SORT -- value 1.
purpose:
Terminates a connection.
Is used by the system to terminate all connections.
restrictions:
You should always pass the handle that you received from
the ESTABLISH method as the JOBJ and not pass any
second argument (defaults to zero).
You may not run this method asynchronously to the caller.
function:
If flags are NULL, then simply removes the connection
that that handle symbolizes. If this is the last
connection, and if the AUTOREMOVE flag was specified in
the INIT method, then the Director is Remove()'d from the
system.
Otherwise, if SHADOW_SORT is specified, the first handle
on the list that is stored as being authorized by the
passed object is terminated.
Uses RemoveClassWatcher() or RemoveWatcherNode()
internally to remove the watcher from the watching-list.
Please see the AutoDocs for more information on these
functions.
example:
see the METH_DIRECTOR_ESTABLISH method example for this
class above.
METH_DIRECTOR_NOTIFY
run as:
function in invoker's process.
arguments:
long -- Flags specifying what changed.
APTR -- A pointer to the WatchedVariable that caused the
notification. Note: this pointer will NOT be
valid if sent ASYNC! This implies that the method
to which notification is sent might also inherit
nonsense in this value, so don't do anything
brash with the NOTIFY method!
APTR -- The new node/value of the WatchedVariable. Once
again, ASYNC causes nightmares.
JSTR -- The name of the new node, if specified.
purpose:
A change occurred someplace that this watcher was watching.
The system calls this function with the correct flags and
arguments, depending on the type of change that occurred.
restrictions:
You may not run this method asynchronously to the caller.
You should not have to call this method directly. Instead,
use the library function call, WatcherDispatch().
function:
If this Director is interested in the particular piece of
information being broadcast, then notification is sent out.
The following are the flags that effect this control.
These are the flags in the lower 16bits of the flags field
sent to the INIT function.
/*
* Match either.
*/
#define W_CHANGE_ZERO 1
#define W_CHANGE_NON_ZERO 2
#define W_CHANGE_VALUE 3
/*
* Match exactly
*/
#define W_NODE 4
#define W_WATCH_CHANGE 8
#define W_REMOVE 16
#define W_INSERT 32
/*
* Control matching.
*/
#define W_MATCH 64
#define W_MATCH_VALUE W_MATCH
#define W_SECOND 128
#define W_MATCH_FIRST W_MATCH
#define W_MATCH_SECOND (W_SECOND | W_MATCH)
#define W_INSERT_NODE (W_NODE | W_INSERT)
#define W_REMOVE_NODE (W_NODE | W_REMOVE)
#define W_INSERT_WATCHER (W_WATCH_CHANGE | W_INSERT)
/* Not valid during... */
#define W_REMOVE_WATCHER (W_WATCH_CHANGE | W_REMOVE)
/* ... INIT[]/DESTROY[] */
The first three flags apply only to non-(list/tree)
variables. IE: the simple longword type of watched
variable -- the WatchedValue. W_CHANGE_ZERO is for when
the variable changes to a zero, W_CHANGE_NON_ZERO is for
when a variable changes to a non-zero, and W_CHANGE_VALUE
is for when either happens. Note that the value may have
already been zero or non-zero. You may use the
W_WATCH_CHANGE to indicate that you don't want to hear
about updates to the variables that don't actually CHANGE
the value that has already been stored [V5].
W_NODE is for any addition or removal of nodes from lists or
trees. W_WATCH_CHANGE, in conjunction with W_INSERT and
W_REMOVE, sends notification out when a watcher is added.
A watcher can get notification when it adds itself, but not
when it removes itself -- sorry, you'll have to use two
watchers for that.... W_REMOVE and W_INSERT control
whether you want notification when something is added or
removed to/from the list/tree.
W_MATCH is used for a simple matching capability. You can
watch for a particular object to be removed from the tree,
or added to the tree, or whatever.... For example, you
might want to know when a -particular- class was created.
W_MATCH_FIRST uses the value sent to the INIT function as
the value of, either:
(a) the value that the WatchedVariable should take on.
(b)the address of the object added to a list/tree.
depending on the type of WatchedVariable.
W_MATCH_SECOND uses the value sent to the INIT function
as the address of a string which would be the name under
which the node is added to the list/tree.
example:
You should not have to call this method directly. Instead,
use the library function call, WatcherDispatch().
/*
* This is roughly the definition of
* RemoveWatchedTreeStringNode()
*
* node is the node to remove
*/
UseObject(node);
if (ret = RemoveTreeStringNode(&(bt->wv_value), node, name))
{
WatcherDispatch(W_REMOVE_NODE,
(struct WatchedValue *)bt,
node,
name);
}
DropObject(node);
return ret;
Modified Methods
METH_DESTROY
run as:
function in invoker's process.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
function:
Name is Drop()'d from the ATTR_MANAGER node->mnn_name field.
If W_SECOND was specified during the METH_INIT, the
node->mnn_value is Drop()'d as well.
Method is then routed to the superclass.
If invoked asynchronously, the object pointer is
transferred out of the msg.
example:
See example under META_CLASS
METH_INIT
run as:
function in invoker's process.
arguments:
JSTR -- the name of the object.
JOBJ -- object to send the notification method to.
JSTR -- the notification method.
long -- various flags controlling the type of watcher
(object or class), the function of the
notification, etc.
long -- optional value for the W_SECOND or W_MATCH_FIRST
flags. If W_SECOND is specified in the flags
field, then this method cannot be invoked
asynchronously, because this would be a pointer
to a string....
returns the initialized object, or NULL on failure.
purpose:
Initializes the object and makes it possible to
ESTABLISH connections with it.
restrictions:
Sending this method asynchronously may be dangerous,
depending on what type the last argument to the method is.
Care must be taken if you want to send this as an
asynchronous method.
function:
As with all INIT functions, if the object is not
successfully INIT'd, the object is UseObject()'d and
DropObject()'d, resulting in an invocation of the
METH_DESTROY function. Usually, the party interested in
receiving notification is UseObject()'d and stored in the
ATTR_MANAGER's node->mnn_method and node->mnn_object.
The name is used and put into the structure at
node->mnn_name. If W_SECOND is specified in the flags
field, the optional value is treated as a string. In
addition, this function parcels the long flags value into
its pieces. The bottom 16 bits become the instrument that
controls when the Director sends out its notification.
The next eight bits has only one flag allocated that
distinguish between SHADOW_OBJECT and SHADOW_CLASS types
of Directors. (One watches a particular object, the other
watches all objects in a class.) The last eight bits
control the working of the internal resource tracking.
One bit is the SHADOW_AUTOREMOVE. When specified, the
last connection TERMINATion causes a METH_REMOVE to be sent
to itself. The other bit is the SHADOW_AUTOBREAK flag.
When it is specified, the REMOVE method automatically
TERMINATEs all connections. Unless you do something very
bizarre, you should specify both bits. An internal bit
(SHADOW_REMOVED) prevents an infinite recursion when both
bits are specified.
You can control the notification so that it occurs only on
specific types of events. This is controlled by the first
16 bits of the 'flags' parameter. The W_* flags which
control the notification restriction are specified in the
method immediately above this one.
Method then is routed to the superclass.
example:
see the METH_DIRECTOR_ESTABLISH method example for this
class above.
METH_REMOVE
run as:
function in invoker's process.
arguments:
none
purpose:
Removes the object from the system and makes it impossible
to ESTABLISH further connections.
May also disengage any current connections if
SHADOW_AUTOBREAK was specified during the METH_INIT.
restrictions:
none
function:
If the Director had its SHADOW_AUTOBREAK specified, all
connections are TERMINATEd. The notification destination
object and method are Drop()'d, cleared.
Method is then routed to the superclass.
example:
see the METH_DIRECTOR_ESTABLISH method example for this
class above.
Class: PATCHER_CLASS
Superclass: ROOT_CLASS
Include File: <shadow/method.h>
The class that creates patches on pre-existing methods.
Attributes:
ATTR_METHODHANDLER -- struct MethodHandler followed by a class
pointer which indicates the class that was
patched. [Attribute is located at address
offset of eight from the object, this
behaviour is depended on by the OS.]
Modified Methods:
METH_DESTROY
run as:
function in invoker's prcoess.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
function:
Drop()s the procObject, defnObject and MethodID of the
patch. Invokes the superclass, then transfers the object
from the msg so that it will work properly when/if invoked
asynchronously.
example:
See example under META_CLASS
METH_INIT
run as:
function in invoker's process.
arguments:
APTR -- A MethodTag. This does NOT cause problems for
ASYNC methods....
JOBJ -- class to patch, or an object of that class; in
which case, unless the object has an
ATTR_PATCHEDVERBS attribute, the class of the
passed object, not the passed object, is patched.
returns the initialized object, or NULL on failure.
purpose:
Initializes the object and installs the patch.
restrictions:
You should be prepared to handle the patched method before
invoking this method.
function:
Usually, the method to be patched is found (failure to
find the method in the class requested causes the patch
to fail -- DOES NOT CHECK superclasses!), procObject and
defnObject in the MethodTag fields are Use()'d and put
into the ATTR_METHODHANDLER. MethodID is also Use()'d.
In addition, all other MethodTag information is copied into
the MethodHandler structure. Class information is saved in
the patched-class field -- this is NOT Use()'d! Patch is
inserted.
Method is then routed to the superclass.
example:
/*
* The patch data (usually a global)
*
* This method returns stuff in both d0 and d1, hence its
* prototype as 'double'. If D1 is non-zero, the patches
* with lower priority (this includes the method itself)
* are called. If D1 is zero, the method invocation
* process is terminated.
*/
extern double PreTestMethod(METHOD_ARGS);
METHOD_TAG preMethod =
{
"Method TEST",
NULL, NULL,
INVOKE_SYNC,
METH_FLAG_CHECK_CONTINUE |
METH_FLAG_CLASS,
1, /* The priority */
(METHODFUNCTYPE)PreTestMethod, NULL
};
/*
* Add a method patch.
* Note we CANNOT use SetupMethodTags!
*/
preMethod.mtag_procObject = dosTaskClass;
preMethod.mtag_defnObject = CurrentProcess();
prePatch = CreateInstance(NULL, PATCHER_CLASS,
META_CLASS,
&preMethod,
my_dos_class, /*
* Actual
* instance
* of
* class.
*/
METHOD_END);
.
.
.
/*
* Cleanup
*/
RemoveObject(prePatch);
METH_REMOVE
run as:
function in invoker's process.
arguments:
none
purpose:
Removes the object and the patch from the system.
restrictions:
none
function:
Patch is removed from the ATTR_PATCHEDVERBS list of the
class that this object is patching.
Method is then routed to the superclass.
example:
see the METH_INIT method example for this class above.
Class: PROCESS_CLASS
Superclass: ROOT_CLASS
Include File: <shadow/process.h>
The class that creates processes.
Attributes:
ATTR_JAZZPROCESS -- struct JazzProcess. Again, the system expects
to find this attribute at offset 8. Do not
hack around and move it, please.
ATTR_RESOURCETREE -- Watched binary tree that you can store
your resources on.
ATTR_RESOURCESTACK -- Watched list that you can store last
minute removal resources. Freed only
during The DISASSOCIATE method.
New Methods:
METH_PROC_ASSOCIATE
run as:
function in invoker's process.
purpose:
Completes the initialization of the object and allocates
the process' ports. Certain things need to be allocated
inside of a process' context (like signals, ports, etc.),
so this method exists to allow you to do our allocation
at this time.
restrictions:
This method should only be invoked in the context of a
currently running process. The METH_INIT handles
this correctly for new processes, InitOOProgram()
handles a default version for the programs you start
up.
If compiling with the small data model, you must call
either the equivalent of geta4() or prototype your
method-function with the __saveds keyword.
arguments:
JSTR -- name of the current process. Defaults to
FindTask(NULL)->tc_node.ln_Name
TASK -- pointer to the task. Defaults to
FindTask(NULL). Needs to be run in the
that task's frame anyway, because Signals
for message ports are allocated....
returns object which should NOT be DROP()'d! This is
safe because the method can only be invoked in that
process to begin with....
function:
Creates a SHADOW process object for a process that already
exists. Stores the object into task->tc_UserData.
Creates ports and synchronous messages for this
process.
Sends the METH_INIT method to the class' superclass -- the
ROOT_CLASS.
example:
/*
* This is roughly the source to InitOOProgram()
*/
procClass = FindShadowClass(PROCESS_CLASS);
myProc = DoShadow(procClass,
NULL,
METH_CREATE,
METHOD_END);
myProc = DoShadow(myProc,
NULL,
METH_PROC_ASSOCIATE,
name,
METHOD_END);
DropObject(procClass);
.
.
.
/*
* Don't forget to call the RemoveCurrentProgram()
* function or some equivalent during cleanup!
*/
METH_PROC_DISASSOCIATE
run as:
function in process associated with the object that
the method is being invoked on.
arguments:
none
purpose:
Completes the process end of the process destruction.
Certain items under AmigaDOS must be freed in the
process that allocated them -- like ports and signals.
This method allows you someplace to put such items.
restrictions:
This is a system invoked method similar to METH_DESTROY.
You may subclass this method, but do not call it.
Again, be careful about the small data model (see above
method).
function:
Shuts various system ports, handles remaining messages,
leaves the ports, deletes the synchronous message.
Removes all the resources (RemoveResources(object, TRUE)).
Deletes the process name.
When the method returns, the system will call the
METH_DESTROY on the process object's superclass to complete
the object destruction. The process will then return to
AmigaDOS.
example:
You should never call this function.
Process cleanup is automatic when a -created- program
exits. When an Amiga-launched app ends, the programmer
should call RemoveCurrentProgram().
METH_PROC_HANDLER
run as:
function in process associated with the object that
the method is being invoked on.
arguments:
none
purpose:
Handles all incoming SHADOW messages. You can subclass
this and override this behaviour to include intercepting
Intuition events as well....
restrictions:
This method should only be invoked in the context of a
currently running process. The METH_INIT handles
this correctly for new processes, no handling is done
for your own program -- you decide where to finally
wait for all the mehods....
If compiling with the small data model, you must call
either the equivalent of geta4() or prototype your
method-function with the __saveds keyword.
function:
Processes all SHADOW messages.
Leaves when ^C is detected.
example:
From <shadow/shadow_proto.h>
DoShadow(CurrentProcess(), NULL, METH_PROC_HANDLER,
METHOD_END);
The METH_PROC_HANDLER is automatically called for
SHADOW-launched prcesses.
Modified Methods:
METH_DESTROY
run as:
function in invoker's process.
arguments:
none
purpose:
METH_DESTROY frees an object.
When DropObject() notices that the usecount has fallen to
zero, it invokes the METH_DESTROY method on the object.
restrictions:
You should never invoke this method yourself!
This method is always invoked by DropObject()!
This method MUST ALWAYS BE INVOKE_CALL! Never
subclass this method to be INVOKE_SYNC or INVOKE_MSG_SYNC.
function:
ATTR_RESOURCETREE is freed.
The SHADOW_PROC_FLAGS_DESTROYED bit is set to inform the
process that it should really go away. A ^C is sent
to the associated process to tell it to go away.
Upon receipt of these signals, the METH_PROC_HANDLER
should return. The system will then call the
METH_PROC_DISASSOCIATE and then the METH_DESTROY on the
superclass of process class, the root class.
If there is no associated process (ie: if the METH_INIT
didn't work properly), the superclass is called directly.
example:
See example under META_CLASS
METH_INIT
run as:
function in invoker's process.
arguments:
JSTR -- name of the process to create.
JOBJ -- The parent object. if no parent object, the
calling process is used as the parent.
SEMF -- an optional semaphore to own shared by the started
process. Semaphore is Release()'d when task exits.
TAGL -- a NULL terminated array of struct TagItem to send to
the CreateNewProc invok. If the INIT fails AFTER
the process is created, the tags' ti_Tag are set
to TAG_IGNORE, so you don't have to free the
resources that might be in the TAGL if the process
fails to be created. (In fact, the ti_Tags are
set to TAG_IGNORE even if the process successfully
opens.)
APTR -- Pointer to an optional ProcessInitFrame. This is
used as an override array to the ASSOCIATE method
to allow the METH_INIT to initialize other classes
of processes in an arbitrarily coplex manner.
APTR -- Pointer to an optional ProcessHandlerFrame. This is
used as an override array to the HANDLER method
to allow METH_INIT to initialize other classes of
processes in an arbitrarily complex manner.
returns the initialized object, or NULL on failure.
purpose:
Create a new process and get the process up and running.
restrictions:
If the last two fields are used, this function should
not be called asynchronously. The Init and Handler Frames
may grow arbitrarily large in size to account for
HANDLER or ASSOCIATE methods that require a large number
of arguments.
If you pass resources in the tags (like file handles), this
function should, again, not be called asynchronously.
function:
Using the two optional frames (and the local default
frames), the ASSOCIATE and HANDLER methods are preparsed
and sent to the newly created process in the form of
messages (allowing asynchronous, safe startups).
The superclass is NOT called, that's done inside of
the PROC_ASSOCIATE method.
Semaphore Obtain()'d shared, process is created, and various
magic done to ensure a safe startup between processes.
Will set all ti_Tag elements to TAG_IGNORE if process is
successfully started, even if process subsequently shuts
down due to a startup error. This allows you to free
resources correctly (hopefully) when process' fail to start
properly, independent upon whether it was the
CreateNewProc() invocation that failed, or something else....
example:
/*
* This example demonstrates how to get
* the INIT method to invoke a subclassed
* METH_PROC_HANDLER with arguments different from the
* default. In this case, the METH_PROC_HANDLER is
* responsible for defining a new class, so the class
* creation arguments are sent into the METH_PROC_HANDLER.
*
* Also note, this is code from the METH_INIT of this
* process-class, so the METH_INIT is actually sent
* on to the superclass.
*/
struct MyHandlerFrame {
struct ProcessHandlerFrame mf_handlerArgs;
char *mf_newName;
struct MethodTag *mf_methods;
struct AttributeTag *mf_attrs;
void *END;
} mhf;
mhf.mf_handlerArgs.phf_methodID = NULL; /* default! */
/*
* New arguments for the subclassed METH_PROC_HANDLER!
*/
mhf.mf_handlerArgs.phf_args[0] = paramClassName;
mhf.mf_newName = newName;
mhf.mf_methods = methods;
mhf.mf_attrs = attrs;
mhf.END = METHOD_END;
process = DoShadow(object, class->meta_superClass,
MethodID,
processName,
NULL, NULL, NULL,
NULL,
&mhf,
METHOD_END);
return process;
.
.
.
/*
* Cleanup!
*/
RemoveObject(process);
METH_REMOVE
run as:
function in process associated with the object that
the method is being invoked on.
arguments:
none
purpose:
Removes the process object from the system.
restrictions:
none
function:
Sets the Remove flag.
Method is then routed to the superclass.
A call to RemoveResources(object, FALSE) is made.
example:
see the METH_INIT method example for this class above.